//根据生成的VectorSSD索引进行向量检索
//Compile: gcc sift1m.c vectorssd_index.c ../min_list/min_list.c -lm -o sift1m 
/* Run (PVE):
./sift1m vectorssd._disk.index \
~/Code/DiskANN/build/data/sift/sift_query.fbin \
~/Code/DiskANN/build/data/sift/sift_groundtruth.fbin \
~/Code/vector-ssd/faiss_test/centroid.bin \
~/Code/vector-ssd/faiss_test/centroid_info.bin
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "vectorssd_index.h"

int main(int argc, void* argv[]){
    if(argc < 6){
        printf("Exec error, root path of files is not given\n");
        printf("Usage: ./sift1m <vectorssd index file> <query file(.fbin)> <groundtruth file(.fbin)> <centroid file> <centroid info file>\n");
        return -1;
    }

    char* index_file = argv[1];
    char* query_file = argv[2];
    char* gt_file = argv[3];
    char* centroid_file = argv[4];
    char* centroid_info_file = argv[5];
    printf("index file path: %s\n", index_file);
    printf("query file path: %s\n", query_file);
    printf("groundtruth file path: %s\n", gt_file);
    printf("centroid file path: %s\n", centroid_file);
    printf("centroid info file path: %s\n", centroid_info_file);

    int batch_size = 500; //一次性读取并检索多少个向量
    int k=30; //获取前多少个最近向量
    int calculate_k = 10; //计算时的k值，前一个k相当于L的长度
    if(calculate_k > k)
        calculate_k = k;

    //开始读取index文件
    INDEX_HEAD head;
    //加载该索引的信息
    FILE* index_fp = fopen(index_file, "r");
    load_index_file_vectorssd(index_fp, &head);

    //读取向量测试
    NODE_FLOAT* node_float_buf = create_node_float_buffer(&head, VECTORSSD_FORMAT);
    read_node_float_fromfile(index_fp, &head, 0, node_float_buf);
    // print_node_float(&head, node_float_buf);

    //进行检索测试
    //打开并加载sift_query文件
    FILE* query_fp = fopen(query_file, "r");
    VECTOR_FLOAT_ARRAY* vector_float_array = create_vector_float_array(query_fp, batch_size); //从fbin文件的头获取向量的维数
    read_vector_float_array_fromfile(query_fp, 0, batch_size, vector_float_array); //从第0个向量开始，读取batch_size个向量
    // for(int i=0; i<vector_float_array->size; i++){
    //     float* v = get_vector_float(vector_float_array, i);
    //     printf("[Vector %d]:",i);
    //     print_vector_float(v, vector_float_array->dim);
    // }

    //打开并加载sift_groundtruth文件
    FILE* gt_fp = fopen(gt_file, "r");
    GT_ARRAY* gt_array = create_gt_array(gt_fp, k, batch_size);
    //读取gt文件测试
    read_gt_array_fromfile(gt_fp, 0, batch_size, gt_array); //从文件中读取
    //打开聚类信息文件并读取
    FILE* cluster_fp = fopen("/home/gary/Code/vector-ssd/faiss_test/vector_cluster_id.bin", "r");
    unsigned short* clusters = malloc(sizeof(short)*head.total_vectors);
    fread(clusters, sizeof(short), head.total_vectors, cluster_fp);
    // for(int i=0; i<gt_array->count; i++){
    //     unsigned int* gt = get_gt(gt_array, i); //从结构体中取出结果
    //     printf("[GT %d]:",i);
    //     // print_gt_array(gt, gt_array->k);
    //     print_gt_array_cluster(gt, gt_array->k, clusters); //检查最终结果中每个结果向量的聚类
    // }

    //ANN结果测试
    // ANN_RESULT* ann_result = create_ann_result(k, batch_size);
    // int accumulator = 0;
    // for(int i=0; i<batch_size; i++){
    //     unsigned int* ids = get_ann_result_ids(ann_result, i);
    //     float* distances = get_ann_result_distances(ann_result, i);
    //     for(int j=0; j<k; j++){
    //         ids[j]=accumulator++;
    //         distances[j]=ids[j]/2.0;
    //     }
    // }
    // print_ann_result(ann_result, 0);

    CLUSTER_INFO* cluster_info = create_load_cluster_info(centroid_file, centroid_info_file, head.dim);

    //实施完全基于磁盘的搜索
    FILE* debug_file = fopen("stats.csv", "w"); //每个检索向量一行，里面每个数据代表的含义：迭代次数、I/O次数
    char title[] = "iter count, IO count, IO per iter, init time(us), search time(us)\n";
    fwrite(title, 1, strlen(title), debug_file);
 
    ANN_RESULT* ann_result = create_ann_result(k, batch_size);
    int ann_ret = vectorssd_disk_search(index_fp, &head, vector_float_array, k, calculate_k, ann_result, cluster_info, debug_file);
    if(!ann_ret){
        //验证检索精度。结果保存在ann_result中
        calculate_recall(gt_array, ann_result, calculate_k);
        print_ann_result(ann_result, 0);
    }
    
    //善后
    destroy_node_float(node_float_buf);
    destory_vector_float_array(vector_float_array);
    destory_gt_array(gt_array);
    destory_ann_result(ann_result);
    destory_cluster_info(cluster_info);
    fclose(index_fp);
    fclose(query_fp);
    fclose(gt_fp);
    fclose(debug_file);

    return 0;
}